package parser

import (
	"fmt"
	"strings"
)

type Lexer struct {
	jsonString []rune
	pos        int
	length     int
	lines      int
	listener   Listener
	value      string
}

const EOF rune = 0

func (lexer *Lexer) next() rune {
	lexer.pos++
	return lexer.current()
}

func (lexer *Lexer) current() rune {
	if lexer.pos >= lexer.length {
		return EOF
	}
	return lexer.jsonString[lexer.pos]
}

func NewLexer(json string) *Lexer {
	rJson := []rune(json)
	return &Lexer{
		jsonString: rJson,
		pos:        0,
		length:     len(rJson),
		listener: &JsonListener{
			pretty: true,
		},
	}
}

func (lexer *Lexer) Parse() string {
	for lexer.current() != EOF {
		lexer.doParse()
	}
	return lexer.listener.GetValue()
}

func (lexer *Lexer) doParse() {
	ch := lexer.current()
	switch ch {
	case '"':
		lexer.readString()
	case 'n':
		lexer.readConstant("null")
		lexer.listener.EnterNullNode(lexer)
	case 'f':
		lexer.readConstant("false")
		lexer.listener.EnterBoolNode(lexer)
	case 't':
		lexer.readConstant("true")
		lexer.listener.EnterBoolNode(lexer)
	case EOF:
		fmt.Println("解析结束")
	case '/':
		lexer.readComment()
		lexer.listener.EnterCommentNode(lexer)
	case '{':
		lexer.listener.EnterObjectNode(lexer)
		lexer.next()
	case '}':
		lexer.listener.ExitObjectNode(lexer)
		lexer.next()
	case '[':
		lexer.listener.EnterArrayNode(lexer)
		lexer.next()
	case ']':
		lexer.listener.ExitArrayNode(lexer)
		lexer.next()
	case ',':
		lexer.listener.EnterCommaNode(lexer)
		lexer.next()
	case ':':
		lexer.listener.EnterColonNode(lexer)
		lexer.next()
	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '.':
		lexer.readNumber()
	case '\n':
		lexer.newLine()
		lexer.next()
	case '\r', '\t', '\b', '\f', ' ':
		lexer.next()
	default:
		panic(fmt.Sprintf("不能识别的字符'%s',当前位置:%d", string(ch), lexer.lines))
	}
}

func (lexer *Lexer) readNumber() {
	start := lexer.pos
	//尝试读取符号
	ch := lexer.current()
	if ch == '-' || ch == '+' {
		ch = lexer.next()
	}
	//尝试读取纯数字
	numCount := 0
	for ch >= '0' && ch <= '9' {
		ch = lexer.next()
		numCount++
	}
	//尝试读取小数
	if ch == '.' {
		for {
			ch = lexer.next()
			if ch >= '0' && ch <= '9' {
				numCount++
			} else {
				break
			}
		}
	}
	if numCount == 0 {
		panic(fmt.Sprintf("数值格式错误，数字长度为零,位置:%d", lexer.lines))
	}
	if ch == 'L' {
		//长整形
		ch = lexer.next()
	} else if ch == 'F' {
		//单精度浮点
		ch = lexer.next()
		//isFloat = true
	} else if ch == 'D' {
		//双精度浮点
		ch = lexer.next()
	} else if ch == 'e' || ch == 'E' {
		//科学计数法
		ch = lexer.next()
		if ch == '+' || ch == '-' {
			ch = lexer.next()
		}
		for ch >= '0' && ch <= '9' {
			ch = lexer.next()
		}
		if ch == 'D' || ch == 'F' {
			ch = lexer.next()
		}
	}
	if lexer.pos-start == 0 {
		panic(fmt.Sprintf("数值长度为空,位置:%d", lexer.lines))
	}
	lexer.value = string(lexer.jsonString[start:lexer.pos])
	lexer.listener.EnterNumberNode(lexer)
}

func (lexer *Lexer) readString() {
	//TODO:待完善
	escapes := [128]rune{}
	escapes['b'] = '\b'
	escapes['t'] = '\t'
	escapes['n'] = '\n'
	escapes['f'] = '\f'
	escapes['r'] = '\r'
	escapes['\v'] = '\u000B'
	escapes['\\'] = '\\'
	escapes['/'] = '/'

	builder := strings.Builder{}
	for {
		lexer.next()
		ch := lexer.current()
		if ch == '"' {
			lexer.next()
			break
		}
		if ch == '\\' {
			lexer.next()
			ch = lexer.current()
			if int32(len(escapes)) > ch && escapes[ch] != 0 {
				next := escapes[lexer.current()]
				builder.WriteRune(next)
			} else if ch == 'x' {
				panic("TODO")
			} else if ch == 'u' {
				panic("TODO")
			} else {
				builder.WriteByte('\\')
				builder.WriteRune(ch)
			}
		} else if ch == EOF {
			panic("内容已经匹配完,仍然没有匹配到期望的字符:\"" + ",当前位置:" + string(rune(lexer.lines)))
		} else {
			builder.WriteRune(ch)
		}
	}
	lexer.value = builder.String()
	lexer.listener.EnterStringNode(lexer)
}

func (lexer *Lexer) readComment() {
	builder := strings.Builder{}
	lexer.next()
	if lexer.current() != '/' {
		panic("无法识别的字符:" + string(lexer.current()) + ",期望出现的是:/" + ",当前位置:" + string(rune(lexer.lines)))
	}
	for {
		lexer.next()
		ch := lexer.current()
		if ch == '\n' {
			lexer.next()
			break
		}
		builder.WriteRune(ch)
	}
	lexer.value = builder.String()
}

func (lexer *Lexer) readConstant(value string) {
	rStr := []rune(value)
	for i := 0; i < len(rStr); i++ {
		ch := rStr[i]
		if ch != lexer.current() {
			panic("无法识别的字符:" + string(lexer.current()) + ",期望出现的是:" + string(ch) +
				",当前位置:" + string(rune(lexer.lines)))
		}
		lexer.next()
	}
	lexer.value = value
}

func (lexer *Lexer) newLine() {
	lexer.lines++
}
